//
//  T4ConvertObject.m
//  Here
//
//  Created by Xiaohui on 13-8-11.
//  Copyright (c) 2013年 Team4.us. All rights reserved.
//

#import "T4ConvertObject.h"
#import <objc/runtime.h>
#import "T4Marco.h"

@implementation T4ConvertObject

+ (id)convert:(id)anObject
      toClass:(Class)aClass
{
    if (T4_CHECK_CLASS(anObject, NSArray)) {
        return [T4ConvertObject convertFromArray:anObject
                                      toSubClass:aClass];
    } else if (T4_CHECK_CLASS(anObject, NSDictionary)) {
        return [T4ConvertObject convertFromDictionary:anObject
                                           toSubClass:aClass];
    } else {
        return anObject;
    }
}

+ (id)convertFromArray:(NSArray *)array
            toSubClass:(Class)aSubClass
{
    NSAssert(T4_CHECK_CLASS(array, NSArray), @"array is not NSArray");
    NSMutableArray *results = [[NSMutableArray alloc] initWithCapacity:array.count];
    for (id object in array) {
        NSObject *entity = [T4ConvertObject convert:object
                                            toClass:aSubClass];
        [results addObject:entity];
    }
    return results;
}

+ (id)convertFromDictionary:(NSDictionary *)dictionary
                 toSubClass:(Class)aSubClass
{
    NSAssert(T4_CHECK_CLASS(dictionary, NSDictionary), @"dictionary is not NSDictionary");
    NSObject *entity = [[aSubClass alloc] init];
    NSArray *propertyNames = [T4ConvertObject propertyNames:aSubClass];
    for (NSString *propertyName in propertyNames) {
        NSObject *value = [dictionary objectForKey:propertyName];
        [T4ConvertObject entity:entity
                       setValue:value
                    forProperty:propertyName];
    }
    
    return entity;
}

+ (void)entity:(id)entity
      setValue:(id)value
   forProperty:(NSString *)property
{
    if (T4_CHECK_CLASS(value, NSArray)) {
        SEL selector = NSSelectorFromString([NSString stringWithFormat:@"%@_class", property]);
        if ([entity respondsToSelector:selector]) {
            Class subClassName = nil;
            SuppressPerformSelectorLeakWarning(
                subClassName = [entity performSelector:selector]
            );
            value = [T4ConvertObject convertFromArray:value
                                           toSubClass:subClassName];
        }
    } else if (T4_CHECK_CLASS(value, NSDictionary)) {
        SEL selector = NSSelectorFromString([NSString stringWithFormat:@"%@_class", property]);
        if ([entity respondsToSelector:selector]) {
            Class subClassName = nil;
            SuppressPerformSelectorLeakWarning(
                subClassName = [entity performSelector:selector]
            );
            value = [T4ConvertObject convertFromDictionary:value
                                                toSubClass:subClassName];
        }
    }
    
    [entity setValue:value forKey:property];
}

+ (NSArray *)propertyNames:(Class)aClass
{	
	NSMutableArray *propertyNamesArray = [NSMutableArray array];
	unsigned int propertyCount = 0;
	objc_property_t *properties = class_copyPropertyList(aClass, &propertyCount);
	
	for (unsigned int i = 0; i < propertyCount; ++i) {
		objc_property_t property = properties[i];
		const char *name = property_getName(property);
		
		[propertyNamesArray addObject:[NSString stringWithUTF8String:name]];
	}
	free(properties);
	
    return propertyNamesArray;
}

+ (BOOL)isPropertyReadOnly:(Class)aClass
              propertyName:(NSString*)propertyName
{
    const char *type = property_getAttributes(class_getProperty(aClass,
                                                                [propertyName UTF8String]));
    NSString *typeString = [NSString stringWithUTF8String:type];
    NSArray *attributes = [typeString componentsSeparatedByString:@","];
    NSString *typeAttribute = [attributes objectAtIndex:1];
    
    return [typeAttribute rangeOfString:@"R"].length > 0;
}

@end
